package com.cc.app.ui;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.MotionEvent;

import com.cc.app.view.TestView;

import java.util.ArrayList;
import java.util.List;

/**
 * 解锁
 */
public class LockView extends TestView {

    private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);

    private float radius;
    private float gap;

    private List<Point> points = new ArrayList<>();
    private StringBuilder sb = new StringBuilder();

    private boolean over;

    public LockView(Context context) {
        this(context, null);
    }

    public LockView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    private void init() {
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStrokeJoin(Paint.Join.BEVEL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        canvas.translate(getWidth() / 2, getHeight() / 2);

        radius = getWidth() / 10;
        gap = radius * 2;

        paint.setTextSize(96);
        paint.setColor(Color.WHITE);
        paint.setStrokeWidth(2);
        paint.setStyle(Paint.Style.FILL);

        float width = paint.measureText(sb.toString());
        canvas.drawText(sb.toString(), -width / 2, -310, paint);

        paint.setStyle(Paint.Style.STROKE);

        paint.setStrokeWidth(5);
        drawCircle(canvas);

        for (int i = 1; i < points.size(); i++) {
            drawLine(canvas, points.get(i - 1), points.get(i));
        }
        canvas.restore();
    }

    private void drawLine(Canvas canvas, Point p1, Point p2) {
        PointF start = getPointCenter(p1);
        PointF end = getPointCenter(p2);
        paint.setStrokeWidth(15);
        paint.setColor(over ? Color.RED : Color.YELLOW);

        canvas.drawLine(start.x, start.y, end.x, end.y, paint);
    }

    private PointF getPointCenter(Point p) {
        float x = p.x * (radius + gap);
        float y = p.y * (radius + gap);

        return new PointF(x, y);
    }

    private void drawCircle(Canvas canvas) {
        for (int i = -1; i < 2; i++) {
            for (int k = -1; k < 2; k++) {
                paintUnit(canvas, i, k);
            }
        }
    }

    private void paintUnit(Canvas canvas, int x, int y) {
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(10);
        canvas.save();

        canvas.translate(x * (gap + radius), 0);
        canvas.translate(0, y * (gap + radius));

        boolean selected = false;
        for (Point p : points) {
            if (p.equals(x, y)) {
                selected = true;
                break;
            }
        }

        if (selected) {
            paint.setColor(over ? Color.RED : Color.YELLOW);
            paint.setStrokeWidth(15);
        }

        canvas.drawCircle(0, 0, radius, paint);
        paint.setStrokeWidth(10);
        paint.setStyle(selected ? Paint.Style.FILL : Paint.Style.STROKE);

        canvas.drawCircle(0, 0, radius / 4, paint);

        canvas.restore();
    }

    private int getNumber(MotionEvent e) {
        PointF p = new PointF(e.getX(), e.getY());

        p.offset(-getWidth() / 2, -getHeight() / 2);

        out:
        for (int i = -1; i < 2; i++) {
            float offsetX = i * (gap + radius);
            float left = -radius + offsetX;
            for (int k = -1; k < 2; k++) {
                float offsetY = k * (gap + radius);
                float top = -radius + offsetY;

                PointF p0 = new PointF(p.x, p.y);
                if (new RectF(left, top, left + radius * 2, top + radius * 2).contains(p0.x, p0.y)) {
                    Point point = new Point(i, k);

                    if (checkPoint(point)) {
                        points.add(point);
                        int num = i + 3 * k + 5;
                        sb.append(num);
                        return num;
                    }
                }
            }
        }

        return 0;
    }

    private boolean checkPoint(Point point) {
        if (points.isEmpty())
            return true;

        if (points.contains(point))
            return false;

        return true;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                getNumber(event);
                break;

            case MotionEvent.ACTION_MOVE:
                getNumber(event);

                break;

            case MotionEvent.ACTION_UP:
                over = true;

                new Handler().postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        points.clear();
                        sb.delete(0, sb.length());
                        over = false;
                        invalidate();
                    }
                }, 800);

                break;

        }

        invalidate();
        return true;
    }
}
